﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;

namespace PlutoStudio.Data
{
    internal static class MiscExtensions
    {
        public static string Join<T>(this IEnumerable<T> list, string separator)
        {
            return string.Join(separator, list);
        }

        public static object GetDefaultValue(this Type type)
        {
            if (!type.IsValueType)
            {
                return null;
            }
            switch (Type.GetTypeCode(type))
            {
                case TypeCode.Boolean:
                    return false;

                case TypeCode.Char:
                case TypeCode.SByte:
                case TypeCode.Byte:
                case TypeCode.Int16:
                case TypeCode.UInt16:
                case TypeCode.Int32:
                case TypeCode.UInt32:
                    return 0;

                case TypeCode.Int64:
                case TypeCode.UInt64:
                    return 0L;

                case TypeCode.Single:
                    return 0f;

                case TypeCode.Double:
                    return 0.0;

                case TypeCode.Decimal:
                    return 0M;

                case TypeCode.DateTime:
                    return new DateTime();
            }
            if (type == typeof(Guid))
            {
                return new Guid();
            }
            if (type == typeof(DateTimeOffset))
            {
                return new DateTimeOffset();
            }
            if (IsNullable(type))
            {
                return null;
            }
            return Activator.CreateInstance(type);
        }

        public static bool IsDefault(this PropertyInfo property, object item)
        {
            var value = property.GetValue(item, null);
            var defaultValue = property.PropertyType.GetDefaultValue();
            return ValueEquals(value, defaultValue);
        }


        public static bool IsNullable(Type t)
        {
            ArgumentNotNull(t, "t");
            if (t.IsValueType)
            {
                return IsNullableType(t);
            }
            return true;
        }

        public static void ArgumentNotNull(object value, string parameterName)
        {
            if (value == null)
            {
                throw new ArgumentNullException(parameterName);
            }
        }

        public static bool IsNullableType(Type t)
        {
            ArgumentNotNull(t, "t");
            return (t.IsGenericType && (t.GetGenericTypeDefinition() == typeof(Nullable<>)));
        }

        public static bool ValueEquals(object objA, object objB)
        {
            if ((objA == null) && (objB == null))
            {
                return true;
            }
            if ((objA != null) && (objB == null))
            {
                return false;
            }
            if ((objA == null) && (objB != null))
            {
                return false;
            }
            if (!(objA.GetType() != objB.GetType()))
            {
                return objA.Equals(objB);
            }
            if (IsInteger(objA) && IsInteger(objB))
            {
                return Convert.ToDecimal(objA, CultureInfo.CurrentCulture).Equals(Convert.ToDecimal(objB, CultureInfo.CurrentCulture));
            }
            return (((((objA is double) || (objA is float)) || (objA is decimal)) && (((objB is double) || (objB is float)) || (objB is decimal))) && ApproxEquals(Convert.ToDouble(objA, CultureInfo.CurrentCulture), Convert.ToDouble(objB, CultureInfo.CurrentCulture)));
        }

        public static bool IsInteger(object value)
        {
            switch (GetTypeCode(value))
            {
                case TypeCode.SByte:
                case TypeCode.Byte:
                case TypeCode.Int16:
                case TypeCode.UInt16:
                case TypeCode.Int32:
                case TypeCode.UInt32:
                case TypeCode.Int64:
                case TypeCode.UInt64:
                    return true;
            }
            return false;
        }

        public static TypeCode GetTypeCode(object o)
        {
            return Convert.GetTypeCode(o);
        }

        public static bool ApproxEquals(double d1, double d2)
        {
            if (d1 == d2)
            {
                return true;
            }
            double num = ((Math.Abs(d1) + Math.Abs(d2)) + 10.0) * 2.2204460492503131E-16;
            double num2 = d1 - d2;
            return ((-num < num2) && (num > num2));
        }


        public static MemberExpression GetMember(this LambdaExpression expression)
        {
            var body = expression.Body;
            if (body is MemberExpression)
            {
                return (body as MemberExpression);
            }
            else
            {
                return GetMember(body);
            }
        }

        public static MemberExpression GetMember(this Expression body)
        {
            if (body is UnaryExpression)
            {
                return GetMember((body as UnaryExpression).Operand);
            }
            if (body is MemberExpression)
            {
                return (body as MemberExpression);
            }
            return GetMember(body as LambdaExpression);
        }



    }
}
